package frame.dao;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.PropertyAccessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;

import frame.utils.FrameUtils;

/**
 * paginate 方法当前只实现了mysql的连接方式。换做其他数据库还需要重新实现DAO接口
 * @author MR.CUIPENG
 *
 */
public class DAOImpl implements DAO,Serializable{

	/**
	 * to avoid a log4j exception when restart the app
	 */
	private static final long serialVersionUID = 1365148835956814611L;
	
	private JdbcTemplate jdbc;
    @Autowired
	private SqlLoader sqlLoader;
    private Logger logger = Logger.getLogger(getClass());
    
	private Map<String, String> sqls;
	
    public void init(){
    	sqls=sqlLoader.getSqlMap();
    	logger.info("sql集合导入完成！"+sqls);
    }
    
	public void setJdbc(JdbcTemplate jdbc) {
		this.jdbc = jdbc;
	}
	public JdbcTemplate getJdbc() {
		return jdbc;
	}

	@Override
	public <T> T queryObject(String sql, Class<T> t, Object... args) {
		sql = sqlSwapper(sql);
		if(isPrimitive(t)){
			return jdbc.queryForObject(sql, t,args);
		}
		RowMapper<T> rm = ParameterizedBeanPropertyRowMapper.newInstance(t);
		return jdbc.queryForObject(sql, rm,args);
	}

	@Override
	public <T> List<T> queryObjectList(String sql, Class<T> t, Object... args) {
		sql = sqlSwapper(sql);
		if(isPrimitive(t)){
			return jdbc.queryForList(sql,t,args);
		}
		RowMapper<T> rm = ParameterizedBeanPropertyRowMapper.newInstance(t);
		return jdbc.query(sql, rm, args);
	}
	
	@Override
	public Map<String,Object> queryMap(String sql, Object... args){
		   sql = sqlSwapper(sql);
		   return jdbc.queryForMap(sql, args);
	}
	
	@Override
	public List<Map<String, Object>> queryMapList(String sql, Object... args) {
		sql = sqlSwapper(sql);
		return jdbc.queryForList(sql,args);
	}

	@Override
	public int updateMap(String sql, Map<String, ?> data, String... order) {
		sql = sqlSwapper(sql);
		return jdbc.update(sql, FrameUtils.mapValues(data, order));
	}

	@Override
	public <T> int updateObject(String sql, T data, String... order) {
		sql = sqlSwapper(sql);
		int len;
		Object[] args ;
		if(isPrimitive(data.getClass())){
			len = 1;
			args= new Object[len];
			args[0]=data;
		}else{
			args=FrameUtils.beanProperties(data, order);
		}
		
		return jdbc.update(sql, args);
	}

	@Override
	public int[] updateMaps(String sql, List<Map<String, Object>> data, String... order) {
		sql = sqlSwapper(sql);
		int len = order.length;
		List<Object[]> args=new ArrayList<Object[]>(data.size());
		for (Map<String,?> map : data) {
			Object[] arg = new Object[len];
			for(int i=0; i<len; i++){
				arg[i] = map.get(order[i]);
			}
			args.add(arg);
		}
		return jdbc.batchUpdate(sql,args);
	}

	@Override
	public <T> int[] updateObjects(String sql, List<T> data, String... order) {
		//如果data中是基本类型，则不需要抽取bean属性，这种情况也只能传递一个参数，且order可以为空
		sql = sqlSwapper(sql);
		List<Object[]> args=new ArrayList<Object[]>(data.size());
		int len;
		if(isPrimitive(data.get(0).getClass())){
			len=1;
			for (T t : data) {
				Object[] arg = new Object[len];
				arg[0]=t;
				args.add(arg);
			}
		}else{
			len = order.length;
			for (T t : data) {
				Object[] arg = new Object[len];
				PropertyAccessor pa=new BeanWrapperImpl(t);
				for(int i=0; i<len; i++){
					arg[i] = pa.getPropertyValue(order[i]);
				}
				args.add(arg);
			}
		}
		return jdbc.batchUpdate(sql,args);
	}
	
	/*判断一个类是否是基本类型*/
	private <T> boolean isPrimitive(Class<T> t){
		if(Integer.class.equals(t)||Long.class.equals(t)||String.class.equals(t)||
		   Double.class.equals(t)||Float.class.equals(t)||BigDecimal.class.equals(t)||
		   Date.class.equals(t)||Timestamp.class.equals(t)){
		   return true;
		}
		return false;
	}
	
	private String sqlSwapper(String sql) {
		String s=sqls.get(sql);
		if(s!=null){
			sql=s;
		}
		return sql;
	}
	
	@Override
	public int update(String sql, Object... args) {
		sql = sqlSwapper(sql);
		return jdbc.update(sql, args);
	}
	@Override
	public int update(String sql) {
		sql = sqlSwapper(sql);
		return jdbc.update(sql);
	}
	
	@Override
	public int update(String sql, Object[] args, int[] argTypes) {
		sql = sqlSwapper(sql);
		return jdbc.update(sql, args, argTypes);
	}

	@Override
	public <T> Page<T> paginate(Class<T> pageInfo,String sql, int pageStart, int pageSize,String sort,String sortD,Object... args) {
		sql = sqlSwapper(sql);
		/*这种尝试是徒劳的，如果在其他地方为对应的表增加或删除了记录，这里是无法感知的，故记录总数就会停留在第一次查询且查询条件没变的样子*/
//		String pageHash;
//		if(args==null){
//			pageHash=FrameUtils.encryptMD5(sql);
//		}else{
//			pageHash=FrameUtils.encryptMD5(sql, Arrays.asList(args).toString());
//		}
		
		StringBuilder pageSql=new StringBuilder(128);
		pageSql.append(sql);
		if(sort!=null&&sortD!=null){//拼接排序方式
			pageSql.append(" order by ").append(sort).append(" ").append(sortD);
		}
		
		pageSql.append(" LIMIT ").append(pageStart).append(",").append(pageSize);
		
		
		
		String pageCount="select count(1) "+sql.substring(sql.toLowerCase().lastIndexOf("from "));//替换掉 from 之前的部分为select count(1) 

		/*获取当前用户的会话*/
//		Session session=SecurityUtils.getSubject().getSession();
//		Integer total;
//		if(session.getAttribute(pageHash)!=null){
//			/*如果找到，则不进行数据库查询*/
//			total=(Integer)session.getAttribute(pageHash);
//		}else{
//			/*如果没有找到对应的值，则重新查询*/
//			total=queryObject(pageCount, Integer.class, args);
//			session.setAttribute(pageHash, total);
//		}
		Integer total=queryObject(pageCount, Integer.class, args);
		List<T> data= queryObjectList(pageSql.toString(), pageInfo, args);
		Page<T> page=new Page<T>(data, total);
		return page;
	}
	
}
